/*******************************************************************************
 * This file is part of Crunch Graphics.
 *
 * Crunch Graphics is free software: you can redistribute it and/or modify it under the
 * terms of the GNU Lesser General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later version.
 *
 * Crunch Graphics is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with
 * Crunch Graphics.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/

package com.crunch.graphics.gpu;

import javax.media.opengl.GL;
import javax.media.opengl.GL3;
import java.util.Arrays;

/** Encapsulates the draw state on the GPU.
 */
public class GpuDrawState extends GpuObject {
	/** Sets the state of the GPU to the state represented by this object.
	 */
	public void bind() {
		getGpuState().bind(this);
	}

	/** Sets whether primitive restart is enabled.
	 */
	public void setPrimitiveRestartEnabled(boolean e) {
		primitiveRestartEnabled = e;
	}

	/** Returns whether primitive restart is enabled.
	 */
	public boolean isPrimitiveRestartEnabled() {
		return primitiveRestartEnabled;
	}

	/** Sets the primitive restart index.
	 */
	public void setPrimitiveRestartIndex(int index) {
		primitiveRestartIndex = index;
	}

	/** Returns the primitive restart index.
	 */
	public int getPrimitiveRestartIndex() {
		return primitiveRestartIndex;
	}

	/** Sets the clear color.
	 */
	public void setClearColor(float[] color) {
		System.arraycopy(color, 0, clearColor, 0, 4);
	}

	/** Returns the clear color.
	 */
	public float[] getClearColor() {
		return Arrays.copyOf(clearColor, 4);
	}

	/** Sets the clear depth.
	 */
	public void setClearDepth(float depth) {
		clearDepth = depth;
	}

	/** Returns the clear depth.
	 */
	public float getClearDepth() {
		return clearDepth;
	}

	/** Sets the clear stencil.
	 */
	public void setClearStencil(int stencil) {
		clearStencil = stencil;
	}

	/** Returns the clear stencil.
	 */
	public int getClearStencil() {
		return clearStencil;
	}

	GpuDrawState(GpuState state) {
		super(state);
		primitiveRestartEnabled = false;
		primitiveRestartIndex = 0;
		Arrays.fill(clearColor, 0.0f);
		clearDepth = 1.0f;
		clearStencil = 0;
	}

	/** Copy constructor.
	 */
	public GpuDrawState(GpuDrawState other) {
		super(other.getGpuState());
		primitiveRestartEnabled = other.primitiveRestartEnabled;
		primitiveRestartIndex = other.primitiveRestartIndex;
		Arrays.fill(clearColor, 0.0f);
		clearDepth = other.clearDepth;
		clearStencil = other.clearStencil;
	}

	private boolean primitiveRestartEnabled;
	private int primitiveRestartIndex;
	private float[] clearColor = new float[4];
	private float clearDepth;
	private int clearStencil;

	// compares changes against current state and apply differences
	void apply(GpuDrawState currentState) {
		currentState.primitiveRestartEnabled = setStateEnabled(primitiveRestartEnabled, currentState.primitiveRestartEnabled, GL3.GL_PRIMITIVE_RESTART);
		if (primitiveRestartEnabled) {
			if (primitiveRestartIndex != currentState.primitiveRestartIndex) {
				getGpuState().getGl().glPrimitiveRestartIndex(primitiveRestartIndex);
				currentState.primitiveRestartIndex = primitiveRestartIndex;
			}
		}

		if (!Arrays.equals(clearColor, currentState.clearColor)) {
			getGpuState().getGl().glClearColor(clearColor[0], clearColor[1], clearColor[2], clearColor[3]);
			currentState.clearColor = clearColor;
		}

		if (clearDepth != currentState.clearDepth) {
			getGpuState().getGl().glClearDepth(clearDepth);
			currentState.clearDepth = clearDepth;
		}

		if (clearStencil != currentState.clearStencil) {
			getGpuState().getGl().glClearStencil(clearStencil);
			currentState.clearStencil = clearStencil;
		}
	}

	// sets values to the current OpenGL state
	void getCurrentState() {
		primitiveRestartEnabled = getGpuState().getGl().glIsEnabled(GL3.GL_PRIMITIVE_RESTART);
		int[] iBuf = new int[1];
		float[] fBuf = new float[1];

		getGpuState().getGl().glGetIntegerv(GL3.GL_PRIMITIVE_RESTART_INDEX, iBuf, 0);
		primitiveRestartIndex = iBuf[0];

		getGpuState().getGl().glGetFloatv(GL.GL_COLOR_CLEAR_VALUE, clearColor, 0);

		getGpuState().getGl().glGetFloatv(GL.GL_DEPTH_CLEAR_VALUE, fBuf, 0);
		clearDepth = fBuf[0];

		getGpuState().getGl().glGetIntegerv(GL.GL_STENCIL_CLEAR_VALUE, iBuf, 0);
		clearStencil = iBuf[0];
	}
}